/*
 * Copyright (c) zhg2yqq.com Corp.
 * All Rights Reserved.
 */
package com.zhg2yqq.wheels.security.multi;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

import cn.hutool.core.text.CharSequenceUtil;

/**
 * Email登陆
 *
 * @author zhg2yqq, 2023年3月16日
 * @version zhg2yqq v1.0
 */
public class EmailAuthenticationTokenHandler {
    public static final String TYPE = "EMAIL";

    public static class EmailAuthenticationTokenFactory implements IAuthenticationTokenFactory {

        @Override
        public String type() {
            return TYPE;
        }

        @Override
        public CustomAuthenticationToken create(AuthenticationTokenParameter parameter) {
            return new EmailAuthenticationToken(parameter);
        }
    }

    public static class EmailAuthenticationToken extends CustomAuthenticationToken {
        private static final long serialVersionUID = 1L;
        protected final Log logger = LogFactory.getLog(getClass());
        protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();

        public EmailAuthenticationToken(AuthenticationTokenParameter parameter) {
            super(TYPE, parameter.getEmail(), parameter.getCode());
        }

        @Override
        public void prevAuthenticationCheck(TokenCheckHelper checkHelper)
                throws AuthenticationException {
            String actualCode = checkHelper.getSecurityRepository().getCaptcha(getName());
            checkHelper.getSecurityRepository().clearCaptcha(getName());
            if (actualCode == null
                    || !CharSequenceUtil.equals(String.valueOf(getCredentials()), actualCode)) {
                // 验证码异常
                this.logger.debug("Failed to authenticate since no code provided");
                throw new BadCodeException(
                        this.messages.getMessage("CustomAuthenticationToken.badCode", "Bad code"));
            }
            super.prevAuthenticationCheck(checkHelper);
        }

        @Override
        public UserDetails retrieveUser(UserDetailsService userDetailsService)
                throws AuthenticationException {
            if (userDetailsService instanceof CustomUserDetailsService) {
                UserDetails loadedUser = ((CustomUserDetailsService) userDetailsService)
                        .loadUserByEmail(getName());
                if (loadedUser == null) {
                    throw new InternalAuthenticationServiceException(
                            "UserDetailsService returned null, which is an interface contract violation");
                }
                return loadedUser;
            }
            throw new InternalAuthenticationServiceException(
                    "UserDetailsService not support loadUserByPhone, please implements CustomUserDetailsService");
        }
    }
}
